#include "UDPRecvThread.h"
#include "common.h"
#include "global.h"
#include "networkessential.h"
#include "messagetype.h"
#include "messagePickUp.h"
#include "asgka_network.h"
#include "messageCommon.h"
#include "TCPRecvThread.h"
#include "asgka_network.h"

#include <iostream>
using namespace std;

bool UDPRecvThread::m_isrunning = false;

UDPRecvThread::UDPRecvThread()
	:m_member_center(NULL),
	 m_group_center(NULL)
{}

UDPRecvThread::UDPRecvThread(memberCenter *member_center, groupCenter *group_center)
	:m_member_center(member_center),
	 m_group_center(group_center)
{}

UDPRecvThread::~UDPRecvThread()
{
	m_isrunning = false;
}

void UDPRecvThread::init(memberCenter *member_center, groupCenter *group_center)
{
	m_member_center = member_center;
	m_group_center  = group_center;
}

UINT WINAPI UDPRecvThread::threadWork()
{
	int retval;
	cout << "Thread begin!" << endl;
	if (m_isrunning)
		return -1;
	if (m_member_center == NULL)
		return -2;

	void (UDPRecvThread::* handle[10]) (char *, sockaddr_in) = {
		&UDPRecvThread::handleDummy,
		&UDPRecvThread::handleMessageSelfInfo,		// 0x21
		&UDPRecvThread::handleMessageSearch,		// 0x22	
		&UDPRecvThread::handleDummy,
		&UDPRecvThread::handleDummy,
		&UDPRecvThread::handleDummy,
		&UDPRecvThread::handleDummy,
		&UDPRecvThread::handleDummy,
		&UDPRecvThread::handleDummy,
		&UDPRecvThread::handleDummy
	};

	m_isrunning = true;

	SOCKET recvSock = socket(AF_INET, SOCK_DGRAM, 0);
	if (recvSock == INVALID_SOCKET)
	{
		cout << WSAGetLastError() << endl;
		if (WSAGetLastError() == WSANOTINITIALISED)
		{
			cout << "WSA NOT STARTUP!!!" << endl;
		}
		return -1;
	}

	sockaddr_in recvaddr;
	recvaddr.sin_family = AF_INET;
	recvaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	recvaddr.sin_port = htons(UDPRecvPort);
	
	retval = bind(recvSock, (sockaddr *)&recvaddr, sizeof(recvaddr));
	if (retval == SOCKET_ERROR)
	{
		cout << WSAGetLastError() << endl;
		if (WSAGetLastError() == WSANOTINITIALISED)
		{
			cout << "WSA NOT STARTUP!!!" << endl;
		}
		closesocket(recvSock);
		return -1;
	}
	UDPRecvSock = recvSock;

	cout << "while (true)" << endl;
	while (true)
	{
		int i = 0;
		char buf[513] = {0};
		unsigned int messagetype;
		unsigned int message_len;
		sockaddr_in sender_addr;
		memset(&sender_addr, 0, sizeof(sockaddr_in));
		recvDataFrom(recvSock, buf, 512, (sockaddr *) &sender_addr, sizeof(sockaddr_in));  
		messagetype = NetCharToFourBytes<unsigned int> (buf);
		i += IntLength;
		message_len = NetCharToFourBytes<unsigned int> (buf + i);
		i += IntLength;

		if (messagetype <= 0 || messagetype > 0x2a)
		{
			closesocket(recvSock);
			return -2;
		}

		cout << "UDP Message Received from: " << inet_ntoa(sender_addr.sin_addr) << endl;
		cout << "================================================================" << endl;

		cout << "Type of the message: " << messagetype << endl;
		cout << "Length of the message: " << message_len << endl;

		char *messageContent = new char[message_len + 1];
		memset(messageContent, 0, message_len + 1);
		memcpy(messageContent, buf + i, message_len);

		(this->*handle[messagetype - 0x20])(messageContent, sender_addr);

		delete messageContent;
		cout << "================================================================" << endl;
		cout << endl;
	}
}

void UDPRecvThread::handleMessageSearch(char *buf, sockaddr_in addr)
{
	messagePickUp pickupinfo(buf);
	std::string sendername;
	pickupinfo.pickUpInfo(sendername);

	if (localname.compare(sendername) == 0)
		return ;
	cout << "Sender name: " << sendername << endl;

	// Reply the message
	messageBase *message = new messageCommon(localname, NET_MESSAGE_SELF_INFO);
	addr.sin_port = htons(UDPRecvPort);
	sendMessageByNetAddr(message, addr);
}

void UDPRecvThread::handleMessageSelfInfo(char *buf, sockaddr_in addr)
{
	std::string sendername;
	messagePickUp pickupinfo(buf);
	pickupinfo.pickUpInfo(sendername);

	cout << "Sender name:" << sendername << endl;

	EnterCriticalSection(&globalcs);
	bool ex = m_member_center->isMemberExisted(sendername);
	LeaveCriticalSection(&globalcs);

	if (ex)
		return;
	
	
	sockaddr_in conaddr;
	conaddr.sin_family = AF_INET;
	conaddr.sin_port = htons(TCPListenPort);
	conaddr.sin_addr = addr.sin_addr;

	singleMember *pMember = NULL;
	int retval;
	SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
	retval = connect(sock, (struct sockaddr *) &conaddr, sizeof(struct sockaddr_in));

	cout << "Now connect to " << sendername << endl;

	// Success
	if (retval == 0)
	{
		cout << "TCP connection established!" << endl;
		messageBase *message = new messageCommon(localname, NET_MESSAGE_SELF_INFO);
		sendMessageBySocket(message, sock);
		EnterCriticalSection(&globalcs);
		pMember = m_member_center->createMember(sendername, conaddr.sin_addr.S_un.S_addr, sock);
		LeaveCriticalSection(&globalcs); 
	}

	if (pMember == NULL)
		closesocket(sock);
	else
	{
		TCPRecvThread *tempThread = new TCPRecvThread(pMember, m_group_center, m_member_center);
		tempThread->start();
		cout << "TCPRecvThread start!" << endl;
	}
}

void UDPRecvThread::handleDummy(char *str, sockaddr_in addr)
{
}
